package com.xingfei.blog.service;

import com.alibaba.fastjson.JSON;
import com.xingfei.blog.common.model.RegisterVo;
import com.xingfei.blog.constants.ErrorConstants;
import com.xingfei.blog.constants.GeneralConstants;
import com.xingfei.blog.dto.*;
import com.xingfei.blog.redisCluster.RedisClusterUtil;
import com.xingfei.blog.result.ServiceResult;
import com.xingfei.blog.util.TopicConsumerUtil;
import com.xingfei.blog.utils.*;
import com.xingfei.blog.vo.ArticleVo;
import com.xingfei.blog.vo.UserInfoVO;
import com.xingfei.blog.vo.UserVO;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import weibo4j.Users;
import weibo4j.model.User;
import weibo4j.model.WeiboException;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Map;


/**
 * Created by xingfei on 2017/1/16.
 */
@Service("webUserService")
public class WebUserService {

    //日志
    private final static Logger logger = LoggerFactory.getLogger(WebUserService.class);

    private static String Profix_User = "user:";

    private static String Profix_qq = "qq:";

    private static String Profix_weibo = "weibo:";

    @Autowired
    private BlogUserService blogUserService;
    @Autowired
    private BlogUserAttentionService blogUserAttentionService;
    @Autowired
    private RedisClusterUtil redisCluster;

    @Value("${spring.activemq.broker-url}")
    private String brokerurl;

    @Value("${spring.activemq.user}")
    private String username;

    @Value("${spring.activemq.password}")
    private String password;

    // 图片域名获取
    @Value("${jianyi.imageDomainUrl}")
    private String imageDomainUrl;

    @Autowired
    private WebMessageService webMessageService;

    @Autowired
    private WebArticleService webArticleService;

    @Autowired
    private WebUserInfoService webUserInfoService;

    /**
     * 根据id查询用户信息
     *
     * @param userId
     * @return
     */
//    @Cacheable(value = "webCache", key = "'findUserByIdWeb:'+#userId.toString()", cacheManager = "cacheManager")
    public UserVO findUserByUserId(Long userId) {
        ServiceResult<UserDTO> serviceResult = this.blogUserService.findUserById(userId);
        if (serviceResult != null && serviceResult.getCode() == ErrorConstants.RES_SUCCESS) {
            UserDTO userTO = serviceResult.getResult();
            //转换数据
            if (userTO != null) {
                UserVO userVO = new UserVO();
                BeanUtils.copyProperties(userTO, userVO);
                return userVO;
            }
        }
//            UserDTO userTO = this.blogUserService.getUserById(userId);
//            //转换数据
//            if (userTO != null) {
//                UserVO userVO = new UserVO();
//                BeanUtils.copyProperties(userTO, userVO);
//                return userVO;
//            }
        return null;
    }


    /**
     * 根据用户id修改用户数据
     *
     * @param userVO
     * @return
     */
    public Integer updateUserAndUserInfo(UserVO userVO) {
        if (userVO == null) return 0;
        UserDTO userDTO = new UserDTO();
        userDTO.setId(userVO.getId());
        userDTO.setEmail(userVO.getEmail());
        UserInfoDTO userInfoDTO = new UserInfoDTO();
        userInfoDTO.setUserId(userVO.getId());
        userInfoDTO.setUserName(userVO.getUsername());
        userInfoDTO.setEmail(userVO.getEmail());
        ServiceResult<Integer> serviceResult = this.blogUserService.updateUserAndUserInfo(userDTO, userInfoDTO);
        if (serviceResult != null && serviceResult.getCode() == ErrorConstants.RES_SUCCESS) {
            return serviceResult.getResult();
        }
        return 0;
    }

    /**
     * 重载上述方法
     * @param userDTO
     * @return
     */
    public Integer updateUserAndUserInfo(UserDTO userDTO) {
        if (userDTO == null) return 0;
        UserInfoDTO userInfoDTO = new UserInfoDTO();
        userInfoDTO.setUserId(userDTO.getId());
        if(userDTO.getUserName()!=null){
            userInfoDTO.setUserName(userDTO.getUserName());
        }
        if(userDTO.getEmail()!=null){
            userInfoDTO.setEmail(userDTO.getEmail());
        }
        if(userDTO.getPhone()!=null){
            userInfoDTO.setPhone(userDTO.getPhone());
        }
        ServiceResult<Integer> serviceResult = this.blogUserService.updateUserAndUserInfo(userDTO, userInfoDTO);
        if (serviceResult != null && serviceResult.getCode() == ErrorConstants.RES_SUCCESS) {
            return serviceResult.getResult();
        }
        return 0;
    }

    /**
     * 根据用户id修改用户数据（邮箱注册，特殊处理）
     *
     * @param userVO
     * @return
     */
    public String updateUserAndUserInfo4Email(UserVO userVO, HttpServletRequest request) {
        if (userVO == null) return null;
        UserDTO userDTO = new UserDTO();
        userDTO.setId(userVO.getId());
        userDTO.setEmail(userVO.getEmail());
        userDTO.setPhone(userVO.getPhone());
        UserInfoDTO userInfoDTO = new UserInfoDTO();
        userInfoDTO.setUserId(userVO.getId());
        userInfoDTO.setUserName(userVO.getUsername());
        userInfoDTO.setPhone(userVO.getPhone());
        ServiceResult<Integer> serviceResult = this.blogUserService.updateUserAndUserInfo(userDTO, userInfoDTO);
        if (serviceResult != null && serviceResult.getCode() == ErrorConstants.RES_SUCCESS) {
            //生成token
            //注册成功，将用户token放入redis，用于下次登录
            String ip = IPUtil.getLocalIp(request);
            //设置token ip+时间戳
            String token = MD5Util.getMD5(ip + System.currentTimeMillis());
            //校验通过，保存进redis
            userDTO.setId(userVO.getId());
            String value = JSON.toJSONString(userDTO);
            //RedisUtil.set(token, value, Integer.valueOf(60 * 30), 1);
            redisCluster.set(token, value, Integer.valueOf(60 * 30));
            return token;
        }
        return null;
    }

    /**
     * 用户注册
     *
     * @param email
     * @param password
     * @return
     */
    public Integer saveUser(String phone, String email, String password) {
        UserDTO userDTO = new UserDTO();
        userDTO.setPhone(phone);
        userDTO.setEmail(email);
        userDTO.setPassword(password);
        ServiceResult<Integer> serviceResult = this.blogUserService.saveUser(userDTO);
        if (serviceResult != null && serviceResult.getCode() == ErrorConstants.RES_SUCCESS) {
            return serviceResult.getResult();
        }
        return ErrorConstants.RES_SERVICE;
    }

    /**
     * 用户注册信息
     *
     * @param registerVo
     * @return
     */
    public String saveUserAndSaveUserInfo(RegisterVo registerVo, HttpServletRequest request, UserDTO userDTO) {
        String token = null;
        if (registerVo != null) {
            try {
                if (StringUtils.isNotEmpty(registerVo.getPassword())) {
                    registerVo.setPassword(MD5Util.getMD5(DESUtil.decryption(registerVo.getPassword(), GeneralConstants.DES_DECODE_KEY)));
                }
                UserInfoDTO userInfoDTO = new UserInfoDTO();
                buildUserDTOByRegisterVo(registerVo, userDTO, userInfoDTO);
                //注册用户，并同时生成用户信息
                ServiceResult<Long> serviceResult = this.blogUserService.saveUserAndSaveUserInfo(userDTO, userInfoDTO);
                if (serviceResult != null && serviceResult.getCode() == ErrorConstants.RES_SUCCESS) {
                    if (serviceResult.getResult() != null && serviceResult.getResult() > 0) {
                        //注册成功，将用户token放入redis，用于下次登录
                        String ip = IPUtil.getLocalIp(request);
                        //设置token ip+时间戳
                        token = MD5Util.getMD5(ip + System.currentTimeMillis());
                        //校验通过，保存进redis
                        userDTO.setId(serviceResult.getResult());
                        String value = JSON.toJSONString(userDTO);
                        //用户选择的记住密码，设置redis缓存时间和cookie时间一致为30天
                        //RedisUtil.set(Profix_User + token, value, Integer.valueOf(60 * 60 * 24 * 30), 1);
                        redisCluster.set(Profix_User + token, value, Integer.valueOf(60 * 60 * 24 * 30));
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
                logger.error("WebUserService.saveUserAndSaveUserInfo error={}", e.getMessage());
            }
        }
        return token;
    }

    /**
     * 通过注册对象封装userDTO
     *
     * @param registerVo
     * @param userDTO
     */
    private void buildUserDTOByRegisterVo(RegisterVo registerVo, UserDTO userDTO, UserInfoDTO userInfoDTO) {
        BeanUtils.copyProperties(registerVo, userDTO);
        BeanUtils.copyProperties(registerVo, userInfoDTO);
    }

    /**
     * 登陆
     */
    public String login(String userName, String password, String ip, String remember, String webToken) {
        //判断用户名是手机号/邮箱
        boolean flag = ValidateUtil.checkEmail(userName);
        ServiceResult<UserDTO> serviceResult = null;
        if (flag) {
            //qq绑定登陆的情况处理
            if (StringUtils.equals(remember, "2") && StringUtils.isNotBlank(webToken)) {
                //查询用户信息并与qq绑定
                serviceResult = blogUserService.getUserInfoByEmailAndBindQQOrWeiBo(userName, webToken, Profix_qq);
            } else if (StringUtils.equals(remember, "3") && StringUtils.isNotBlank(webToken)) {
                //查询用户信息并与weibo绑定
                serviceResult = blogUserService.getUserInfoByEmailAndBindQQOrWeiBo(userName, webToken, Profix_weibo);
            } else {
                serviceResult = blogUserService.findUserByEmail(userName);
            }

        } else {
            //qq绑定登陆的情况处理
            if (StringUtils.equals(remember, "2") && StringUtils.isNotBlank(webToken)) {
                serviceResult = blogUserService.getUserInfoByPhoneAndBindQQOrWeiBo(userName, webToken, Profix_qq);
            } else if (StringUtils.equals(remember, "3") && StringUtils.isNotBlank(webToken)) {
                serviceResult = blogUserService.getUserInfoByPhoneAndBindQQOrWeiBo(userName, webToken, Profix_weibo);
            } else {
                serviceResult = blogUserService.findUserByPhone(userName);
            }
        }
        if (serviceResult != null && serviceResult.getCode() == ErrorConstants.RES_SUCCESS) {
            UserDTO userTO = serviceResult.getResult();
            //转换为VO模型对象存储redis
            UserInfoDTO userInfoDTO = userTO.getUserInfoDTO();
            UserInfoVO userinfoVO = null;
            if (userInfoDTO != null) {
                userinfoVO = new UserInfoVO();
                BeanUtils.copyProperties(userInfoDTO, userinfoVO);
                if(StringUtils.isNotBlank(userinfoVO.getAvatarUrl())){
                    userinfoVO.setAvatarUrl(imageDomainUrl+userinfoVO.getAvatarUrl());
                }
            }
            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(userTO, userVO);
            userVO.setUserInfoVO(userinfoVO);
            //校验密码
            if (password.equalsIgnoreCase(userTO.getPassword())) {
                //设置token ip+时间戳
                String token = MD5Util.getMD5(ip + System.currentTimeMillis());
                //校验通过，保存进redis
                String value = JSON.toJSONString(userVO);
                if (StringUtils.equals(remember, "1")) {
                    //用户选择的记住密码，设置redis缓存时间和cookie时间一致为30天
                    //RedisUtil.set(Profix_User + token, value, Integer.valueOf(60 * 60 * 24 * 30), 1);
                    redisCluster.set(Profix_User + token, value, Integer.valueOf(60 * 60 * 24 * 30));
                } else {
                    //30分钟
                    //RedisUtil.set(Profix_User + token, value, Integer.valueOf(60 * 30), 1);
                    redisCluster.set(Profix_User + token, value, Integer.valueOf(60 * 30));
                }
                return token;
            }

        }
        //返回用户null
        return null;
    }

    /**
     * 根据weibo_uid查找用户
     *
     * @param weiboUid
     * @return
     */
    public Long getUserInfoByWeiboUid(String weiboUid) {
        ServiceResult<Long> serviceResult = blogUserService.getUserInfoByWeiboUid(weiboUid);
        if (serviceResult != null && serviceResult.getCode() == ErrorConstants.RES_SUCCESS) {
            Long result = serviceResult.getResult();
            return result;
        }
        return null;
    }

    /**
     * 获取微博用户信息
     */
    public User getUserWeiboInfo(String access_token, String uid) {
        Users um = new Users(access_token);
        try {
            User user = um.showUserById(uid);
            return user;
        } catch (WeiboException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 根据token缓存获取用户信息
     */
    public UserVO getUser4Redis(String token) {
        //String userinfo = RedisUtil.get(Profix_User + token, 1);
        String userinfo = redisCluster.get(Profix_User + token);
        UserVO userVO = JSON.parseObject(userinfo, UserVO.class);
        return userVO;
    }

    /**
     * 根据request 缓存获取用户信息
     */
    public UserVO getUser4Redis(HttpServletRequest request) {
        Cookie[] cookies = request.getCookies();
        if (cookies != null && cookies.length > 0) {
            try {
                Cookie cookie2 = CookieUtil.getCookie(request, "token");
                if (cookie2 != null) {
                    String token = cookie2.getValue();
                    if (StringUtils.isNotEmpty(token)) {
                        UserVO userVO = this.getUser4Redis(token);
                        return userVO;
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
                logger.error("message error:", e);
            }
        }
        return null;
    }

    /**
     * 根据qq openID 判斷是否已綁定用户
     *
     * @param openID
     * @return
     */
    public Long getUserInfoByOpenId(String openID) {
        ServiceResult<Long> serviceResult = blogUserService.getUserInfoByOpenId(openID);
        if (serviceResult != null && serviceResult.getCode() == ErrorConstants.RES_SUCCESS) {
            Long result = serviceResult.getResult();
            return result;
        }
        return null;
    }

    /**
     * qq/weibo 注册用户接口
     *
     * @param userDTO
     * @return
     */
    public boolean thirdRegistAndSaveUserInfo(UserInfoDTO userDTO, HttpServletRequest request, HttpServletResponse response) {
        ServiceResult<UserDTO> serviceResult = blogUserService.thirdRegistAndSaveUserInfo(userDTO);
        if (serviceResult != null && serviceResult.getCode() == ErrorConstants.RES_SUCCESS) {
            UserDTO result = serviceResult.getResult();
            if (result != null) {
                //用户信息缓存进redis
                //转换为VO模型对象存储redis
                UserInfoDTO userInfoDTO = result.getUserInfoDTO();
                UserInfoVO userinfoVO = null;
                if (userInfoDTO != null) {
                    userinfoVO = new UserInfoVO();
                    BeanUtils.copyProperties(userInfoDTO, userinfoVO);
                }
                UserVO userVO = new UserVO();
                BeanUtils.copyProperties(result, userVO);
                userVO.setUserInfoVO(userinfoVO);
                //设置token ip+时间戳
                String ip = IPUtil.getLocalIp(request);
                String token = MD5Util.getMD5(ip + System.currentTimeMillis());
                //校验通过，保存进redis
                String value = JSON.toJSONString(userVO);
                //30分钟
                //RedisUtil.set(Profix_User + token, value, Integer.valueOf(60 * 30), 1);
                redisCluster.set(Profix_User + token, value, Integer.valueOf(60 * 30));
                CookieUtil.setCookieDefault(response, "token", token);
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }

    }

    /**
     * 获取用户详情
     *
     * @param userId
     * @return
     */
    public UserVO getUserAndUserInfoById(Long userId) {
        ServiceResult<UserDTO> serviceResult = this.blogUserService.getUserById(userId);
        UserVO userVO = null;
        if (serviceResult != null && serviceResult.getCode() == ErrorConstants.RES_SUCCESS) {
            UserDTO userDTO = serviceResult.getResult();
            if (userDTO != null) {
                userVO = new UserVO();
                UserInfoVO userInfoVO = new UserInfoVO();
                BeanUtils.copyProperties(userDTO, userVO);
                BeanUtils.copyProperties(userDTO.getUserInfoDTO(), userInfoVO);
                if(StringUtils.isNotBlank(userInfoVO.getAvatarUrl())){
                    userInfoVO.setAvatarUrl(imageDomainUrl+userInfoVO.getAvatarUrl());
                }
                userVO.setUserInfoVO(userInfoVO);
                //获取用户的关注数和粉丝数
                buildUserAttentions(userId, userVO);
            }
        }
        return userVO;
    }

    /**
     * 封装用户关注和被关注数据
     *
     * @param userId
     * @param userVO
     */
    private void buildUserAttentions(Long userId, UserVO userVO) {
        ServiceResult<Map<String, Integer>> attentionsResult = blogUserAttentionService.getAttentionsByUserId(userId);
        if (attentionsResult != null && attentionsResult.getCode() == ErrorConstants.RES_SUCCESS) {
            Map<String, Integer> integerMap = attentionsResult.getResult();
            if (MapUtils.isNotEmpty(integerMap)) {
                Integer attentions = MapUtils.getInteger(integerMap, "attentions");
                if (attentions != null) {
                    userVO.setAttentions(attentions);
                }
                Integer byattentions = MapUtils.getInteger(integerMap, "byattentions");
                if (byattentions != null) {
                    userVO.setBeAttentions(byattentions);
                }
            }
        }
    }

    /**
     * 通过用户名查找用户信息
     *
     * @param username
     */
    public UserVO getUserByUsername(String username) {
        //判断用户名是手机号/邮箱
        boolean flag = ValidateUtil.checkEmail(username);
        ServiceResult<UserDTO> serviceResult = null;
        if (flag) {
            serviceResult = blogUserService.findUserByEmail(username);
        } else {
            serviceResult = blogUserService.findUserByPhone(username);
        }
        if (serviceResult != null && serviceResult.getCode() == ErrorConstants.RES_SUCCESS) {
            UserDTO result = serviceResult.getResult();
            UserVO uv = new UserVO();
            BeanUtils.copyProperties(result, uv);
            return uv;
        }
        return null;
    }

    /**
     * 根据用户名更新密码
     *
     * @return
     */
    public boolean updateUserByUsername(String username, String password) {
        boolean flag = ValidateUtil.checkEmail(username);
        ServiceResult<Integer> serviceResult = null;
        if (flag) {
            serviceResult = blogUserService.updateUserByEmial(username, password);
        } else {
            serviceResult = blogUserService.updateUserByPhone(username, password);
        }
        if (serviceResult != null && serviceResult.getCode() == ErrorConstants.RES_SUCCESS) {
            Integer result = serviceResult.getResult();
            if (result >= 1) {
                return true;
            } else
                return false;
        } else {
            return false;
        }
    }

    /**
     * 抽取登陆成功加载的数据，未读消息/文章列表/activemq 消费者
     */
    public void firstToLoad(HttpServletRequest request, UserVO userVO){
        //从当前线程获取uservo
        UserVO user = UserThreadLocal.get();
        //创建activemq consumer
        TopicConsumerUtil consumer = new TopicConsumerUtil(user.getId(), brokerurl, username, password);
        consumer.initConsumer();
        //加载未读消息
        Map<String, Object> map = webMessageService.getUnreadSecretMessage(user.getId());
        List<SecretMessageDTO> secret_msg = (List<SecretMessageDTO>) map.get("secret_msg");
        List<UserSystemMsgDTO> sys_msg = (List<UserSystemMsgDTO>) map.get("sys_msg");
        int attention_count = map.get("attention_count")==null?0:(int) map.get("attention_count");
        int count = (secret_msg==null?0:secret_msg.size()) + (sys_msg==null?0:sys_msg.size()) + attention_count;
        request.getSession().setAttribute("messages", count==0?null:count);
        request.getSession().setAttribute("secret_msg", secret_msg==null?null:secret_msg.size());
        request.getSession().setAttribute("sys_msg", sys_msg==null?null:sys_msg.size());
        if(attention_count!=0){
            request.getSession().setAttribute("attention_count", attention_count);
        }
        request.getSession().setAttribute("user", user);
        //加载首页文章列表
        ArticleDTO articleDTO = new ArticleDTO();
        articleDTO.setArticleType(1l);
        List<ArticleVo> articleVos = webArticleService.listByPage(articleDTO, 1, GeneralConstants.PAGE_SIZE);
        if (CollectionUtils.isNotEmpty(articleVos)) {
            for (ArticleVo articleVo : articleVos) {
                webArticleService.appendArticleOtherData(articleVo, userVO);
                webArticleService.appendUserInfo(articleVo);
            }
            request.getSession().setAttribute("articles", articleVos);
        }
        List<UserInfoDTO> infoDTOS = webUserInfoService.listRecommendAuthor();
        if (CollectionUtils.isNotEmpty(infoDTOS)) {
            request.getSession().setAttribute("recommends", infoDTOS);
        }
    }

    /**
     * 只加载首页文章
     * @param request
     * @param userVO
     */
    public void firstToLoad2(HttpServletRequest request, UserVO userVO){
        //加载首页文章列表
        ArticleDTO articleDTO = new ArticleDTO();
        articleDTO.setArticleType(1l);
        List<ArticleVo> articleVos = webArticleService.listByPage(articleDTO, 1, GeneralConstants.PAGE_SIZE);
        if (CollectionUtils.isNotEmpty(articleVos)) {
            for (ArticleVo articleVo : articleVos) {
                webArticleService.appendArticleOtherData(articleVo, userVO);
                webArticleService.appendUserInfo(articleVo);
            }
            request.getSession().setAttribute("articles", articleVos);
        }
        List<UserInfoDTO> infoDTOS = webUserInfoService.listRecommendAuthor();
        if (CollectionUtils.isNotEmpty(infoDTOS)) {
            request.getSession().setAttribute("recommends", infoDTOS);
        }
    }
    /**
     *个人中心调用，更新userinfo/user字段
     * @return
     */
    public boolean updateUserInfoField(UserDTO userDTO) {
        Integer integer = this.updateUserAndUserInfo(userDTO);
        if (integer>0) {
            return true;
        } else {
            return false;
        }
    }
}
